--- /dev/null
+No,Latitude,Longitude,Name,Altitude,Description,Notes,Symbol,Date,Time\r
+1,42.438878,-71.119277,"5066",44.6,"5066","5066","Crossing",2001/11/28,22:05:28\r
+2,42.439227,-71.119689,"5067",57.6,"5067","5067","Dot",2001/06/02,05:26:55\r
+3,42.438917,-71.116146,"5096",44.8,"5096","5096","Dot",2001/11/17,00:03:38\r
+4,42.443904,-71.122044,"5142",50.6,"5142","5142","Dot",2001/11/28,22:05:28\r
+5,42.447298,-71.121447,"5156",127.7,"5156","5156","Dot",2001/06/02,05:26:58\r
+6,42.454873,-71.125094,"5224",96.9,"5224","5224","Dot",2001/06/02,05:26:59\r
+7,42.459079,-71.124988,"5229",82.6,"5229","5229","Dot",2001/06/02,05:26:59\r
+8,42.456979,-71.124474,"5237",82.9,"5237","5237","Dot",2001/06/02,05:26:59\r
+9,42.454401,-71.120990,"5254",66.7,"5254","5254","Dot",2001/11/28,22:05:28\r
+10,42.451442,-71.121746,"5258",74.6,"5258","5258","Dot",2001/11/08,00:53:41\r
+11,42.454404,-71.120660,"5264",65.3,"5264","5264","Dot",2001/11/28,22:05:28\r
+12,42.457761,-71.121045,"526708",77.4,"526708","526708","Dot",2001/06/02,05:27:00\r
+13,42.457089,-71.120313,"526750",74.7,"526750","526750","Dot",2001/06/02,05:27:00\r
+14,42.456592,-71.119676,"527614",78.7,"527614","527614","Dot",2001/11/08,00:53:41\r
+15,42.456252,-71.119356,"527631",78.7,"527631","527631","Dot",2001/11/08,00:53:41\r
+16,42.458148,-71.119135,"5278",68.3,"5278","5278","Dot",2001/06/02,05:27:00\r
+17,42.459377,-71.117693,"5289",64.0,"5289","5289","Dot",2001/06/02,05:27:01\r
+18,42.464183,-71.119828,"5374FIRE",53.0,"5374FIRE","5374FIRE","Dot",2001/11/28,22:05:28\r
+19,42.465650,-71.119399,"5376",56.4,"5376","5376","Dot",2001/06/02,05:27:02\r
+20,42.439018,-71.114456,"6006",56.4,"600698","600698","Dot",2001/06/02,05:26:55\r
+21,42.438594,-71.114803,"6006BLUE",46.0,"6006BLUE","6006BLUE","Dot",2001/11/28,22:05:28\r
+22,42.436757,-71.113223,"6014MEADOW",37.6,"6014MEADOW","6014MEADOW","Dot",2001/11/28,22:05:28\r
+23,42.441754,-71.113220,"6029",56.4,"6029","6029","Dot",2001/06/02,05:26:55\r
+24,42.436243,-71.109075,"6053",50.3,"6053","6053","Dot",2001/06/02,05:27:05\r
+25,42.439250,-71.107500,"6066",25.6,"6066","6066","Dot",2001/06/02,05:26:57\r
+26,42.439764,-71.107582,"6067",34.4,"6067","6067","Dot",2001/06/02,05:26:57\r
+27,42.434766,-71.105874,"6071",30.5,"6071","6071","Dot",2001/06/02,05:26:57\r
+28,42.433304,-71.106599,"6073",15.2,"6073","6073","Dot",2001/06/02,05:26:56\r
+29,42.437338,-71.104772,"6084",37.8,"6084","6084","Dot",2001/06/02,05:26:57\r
+30,42.442196,-71.110975,"6130",64.0,"6130","6130","Dot",2001/06/02,05:26:55\r
+31,42.442981,-71.111441,"6131",64.0,"6131","6131","Dot",2001/06/02,05:26:58\r
+32,42.444773,-71.108882,"6153",62.8,"6153","6153","Dot",2001/06/02,05:27:05\r
+33,42.443592,-71.106301,"6171",55.5,"6171","6171","Dot",2001/06/02,05:27:05\r
+34,42.447804,-71.106624,"6176",62.5,"6176","6176","Dot",2001/06/02,05:27:04\r
+35,42.448448,-71.106158,"6177",62.2,"6177","6177","Dot",2001/06/02,05:27:04\r
+36,42.453415,-71.106783,"6272",69.8,"6272","6272","Dot",2001/06/02,05:26:55\r
+37,42.453434,-71.107253,"6272",73.2,"6272","6272","Dot",2001/06/02,05:26:56\r
+38,42.458298,-71.106771,"6278",70.1,"6278","6278","Dot",2001/06/02,05:27:04\r
+39,42.451430,-71.105413,"6280",57.6,"6280","6280","Dot",2001/11/17,00:03:38\r
+40,42.453845,-71.105206,"6283",66.7,"6283","6283","Dot",2001/11/17,00:03:38\r
+41,42.459986,-71.106170,"6289",72.9,"6289","6289","Dot",2001/11/17,00:03:38\r
+42,42.457616,-71.105116,"6297",72.8,"6297","6297","Dot",2001/06/02,05:27:04\r
+43,42.467110,-71.113574,"6328",53.6,"6328","6328","Dot",2001/06/02,05:27:02\r
+44,42.464202,-71.109863,"6354",43.9,"6354","6354","Dot",2001/06/02,05:27:03\r
+45,42.466459,-71.110067,"635722",48.8,"635722","635722","Dot",2001/06/02,05:27:02\r
+46,42.466557,-71.109410,"635783",49.1,"635783","635783","Dot",2001/06/02,05:27:02\r
+47,42.463495,-71.107117,"6373",62.5,"6373","6373","Dot",2001/06/02,05:27:03\r
+48,42.401051,-71.110241,"6634",4.0,"6634","6634","Dot",2001/06/02,05:26:56\r
+49,42.432621,-71.106532,"6979",13.4,"6979","6979","Dot",2001/06/02,05:26:56\r
+50,42.431033,-71.107883,"6997",34.0,"6997","6997","Dot",2001/11/17,00:03:38\r
+51,42.465687,-71.107360,"BEAR HILL",87.8,"BEAR HILL TOWER","Bear Hill Tower","Tall Tower",2001/06/02,05:27:03\r
+52,42.430950,-71.107628,"BELLEVUE",23.5,"BELLEVUE","Bellevue Parking Lot","Parking Area",2001/06/02,02:18:15\r
+53,42.438666,-71.114079,"6016",43.4,"Bike Loop Connector","Bike Loop Connector","Waypoint",2001/11/28,22:05:28\r
+54,42.456469,-71.124651,"5236BRIDGE",89.9,"Bridge","Bridge","Bridge",2001/06/02,05:26:59\r
+55,42.465759,-71.119815,"5376BRIDGE",55.5,"Bridge","Bridge","Bridge",2001/06/02,05:27:01\r
+56,42.442993,-71.105878,"6181CROSS",52.7,"Crossing","Crossing","Crossing",2001/06/02,05:27:05\r
+57,42.435472,-71.109664,"6042CROSS",45.1,"Crossing","Crossing","Crossing",2001/06/02,05:27:05\r
+58,42.458516,-71.103646,"DARKHOLLPO",,"Dark Hollow Pond","Dark Hollow Pond","Fishing Area",,\r
+59,42.443109,-71.112675,"6121DEAD",56.1,"Dead End","Dead End","Danger Area",2001/06/02,05:26:57\r
+60,42.449866,-71.119298,"5179DEAD",117.0,"Dead End","Dead End","Danger Area",2001/06/02,05:26:59\r
+61,42.459629,-71.116524,"5299DEAD",69.5,"Dead End","Dead End","Danger Area",2001/06/02,05:27:01\r
+62,42.465485,-71.119148,"5376DEAD",57.0,"Dead End","Dead End","Danger Area",2001/06/02,05:27:02\r
+63,42.462776,-71.109986,"6353DEAD",46.9,"Dead End","Dead End","Danger Area",2001/06/02,05:27:03\r
+64,42.446793,-71.108784,"6155DEAD",61.3,"Dead End","Dead End","Danger Area",2001/06/02,05:27:04\r
+65,42.451204,-71.126602,"GATE14",110.9,"Gate 14","Gate 14","Truck Stop",2001/06/02,05:26:59\r
+66,42.458499,-71.122078,"GATE16",77.7,"Gate 16","Gate 16","Truck Stop",2001/06/02,05:27:00\r
+67,42.459376,-71.119238,"GATE17",65.8,"Gate 17","Gate 17","Truck Stop",2001/06/02,05:27:01\r
+68,42.466353,-71.119240,"GATE19",57.3,"Gate 19","Gate 19","Truck Stop",2001/06/02,05:27:02\r
+69,42.468655,-71.107697,"GATE21",49.4,"Gate 21","Gate 21","Truck Stop",2001/06/02,05:27:03\r
+70,42.456718,-71.102973,"GATE24",81.1,"Gate 24","Gate 24","Truck Stop",2001/06/02,05:27:03\r
+71,42.430847,-71.107690,"GATE5",21.5,"Gate 5","Gate 5","Truck Stop",2001/11/28,22:05:28\r
+72,42.431240,-71.109236,"GATE6",26.6,"Gate 6","Gate 6","Waypoint",2001/11/08,00:53:41\r
+73,42.439502,-71.106556,"6077LOGS",32.0,"Log Crossing","Log Crossing","Amusement Park",2001/06/02,02:18:16\r
+74,42.449765,-71.122320,"5148NANEPA",119.8,"Nanepashemet Road Crossing","Nanepashemet Road Crossing","Waypoint",2001/11/08,00:53:41\r
+75,42.457388,-71.119845,"5267OBSTAC",73.8,"Obstacle","Obstacle","Amusement Park",2001/06/02,05:27:00\r
+76,42.434980,-71.109942,"PANTHRCAVE",45.3,"Panther Cave","Panther Cave","Tunnel",2001/11/08,00:53:41\r
+77,42.453256,-71.121211,"5252PURPLE",78.0,"Purple Rock Hill","Purple Rock Hill","Summit",2001/11/08,00:53:41\r
+78,42.457734,-71.117481,"5287WATER",68.0,"Reservoir","Reservoir","Swimming Area",2001/06/02,05:27:01\r
+79,42.459278,-71.124574,"5239ROAD",81.1,"Road","Road","Truck Stop",2001/06/02,05:27:00\r
+80,42.458782,-71.118991,"5278ROAD",67.4,"Road","Road","Truck Stop",2001/06/02,05:27:01\r
+81,42.439993,-71.120925,"5058ROAD",53.9,"ROAD CROSSING","Road Crossing","Dot",2001/06/02,02:18:14\r
+82,42.453415,-71.106782,"SHEEPFOLD",69.8,"Sheepfold Parking Lot","Sheepfold Parking Lot","Parking Area",2001/06/02,02:18:13\r
+83,42.455956,-71.107483,"SOAPBOX",64.0,"Soap Box Derby Track","Soap Box Derby Track","Cemetery",2001/06/02,05:27:04\r
+84,42.465913,-71.119328,"5376STREAM",64.5,"Stream Crossing","Stream Crossing","Bridge",2001/11/08,00:53:41\r
+85,42.445359,-71.122845,"5144SUMMIT",61.6,"Summit","Summit","Summit",2001/11/28,22:05:28\r
+86,42.441727,-71.121676,"5150TANK",67.4,"WATER TANK","Water Tank","Museum",2001/06/02,02:18:16\r
/*
Universal CSV - support for csv files, divining field order from the header.
- Copyright (C) 2006 Robert Lipe, robertlipe@usa.net
+ Copyright (C) 2006 Robert Lipe, robertlipe@usa.net,
+ copyright (C) 2007 Olaf Klein, o.b.klein@gpsbabel.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
*/
#include "defs.h"
+#include "cet.h"
+#include "cet_util.h"
#include "csv_util.h"
+#include "garmin_tables.h"
#include "jeeps/gpsmath.h"
#include "strptime.h"
#include <string.h>
+#include <time.h>
#define MYNAME "unicsv"
+/* "UNICSV_FIELD_SEP" and "UNICSV_LINE_SEP" are only used by the writer */
+#define UNICSV_FIELD_SEP ","
+#define UNICSV_LINE_SEP "\r\n"
+#define UNICSV_QUOT_CHAR '"'
+
+/* GPSBabel internal and calculated fields */
typedef enum {
fld_shortname = 0,
fld_latitude,
fld_url,
fld_altitude,
fld_utm_zone,
- fld_utm_char,
+ fld_utm_zone_char,
fld_utm_northing,
fld_utm_easting,
fld_utm,
fld_cadence,
fld_proximity,
fld_depth,
+ fld_symbol,
+ fld_date,
+ fld_time,
+ fld_datetime,
+ fld_iso_time,
fld_terminator
} field_e;
char *name;
field_e type;
gbuint32 options;
-
} field_t;
/*
- * ! Use always underscores in field names !
+ * ! Please use always underscores in field names !
* we check a second time after replacing underscores with spaces
*/
static field_t fields_def[] = {
{ "name", fld_shortname, STR_ANY },
{ "desc", fld_description, STR_ANY },
{ "notes", fld_notes, STR_ANY },
- { "comment", fld_notes, STR_ANY },
+ { "omment", fld_notes, STR_ANY },
{ "text", fld_notes, STR_ANY },
{ "url", fld_url, STR_ANY },
+ { "icon", fld_symbol, STR_ANY },
+ { "symb", fld_symbol, STR_ANY },
{ "lat", fld_latitude, STR_ANY },
{ "lon", fld_longitude, STR_ANY },
{ "x", fld_longitude, STR_EQUAL },
{ "y", fld_latitude, STR_EQUAL },
+ { "z", fld_altitude, STR_EQUAL },
+ { "x_pos", fld_longitude, STR_ANY },
+ { "y_pos", fld_latitude, STR_ANY },
{ "alt", fld_altitude, STR_ANY },
{ "ele", fld_altitude, STR_ANY },
{ "utm_z", fld_utm_zone, STR_ANY },
- { "utm_c", fld_utm_char, STR_ANY },
+ { "utm_c", fld_utm_zone_char, STR_ANY },
+ { "utm_zc", fld_utm_zone_char, STR_ANY },
{ "utm_n", fld_utm_northing, STR_ANY },
{ "utm_e", fld_utm_easting, STR_ANY },
{ "utm", fld_utm, STR_EQUAL },
+ { "utm_coo", fld_utm, STR_ANY },
+ { "utm_pos", fld_utm, STR_ANY },
{ "bng_z", fld_bng_zone, STR_ANY },
{ "bng_n", fld_bng_northing, STR_ANY },
{ "bng_e", fld_bng_easting, STR_ANY },
{ "bng", fld_bng, STR_EQUAL },
+ { "bng_coo", fld_bng, STR_ANY },
+ { "bng_pos", fld_bng, STR_ANY },
{ "hdop", fld_hdop, STR_ANY },
{ "pdop", fld_pdop, STR_ANY },
{ "vdop", fld_vdop, STR_ANY },
{ "utc_d", fld_utc_date, STR_ANY },
{ "utc_t", fld_utc_time, STR_ANY },
{ "head", fld_course, STR_ANY },
- { "course", fld_course, STR_ANY },
+ { "cour", fld_course, STR_ANY },
{ "speed", fld_speed, STR_ANY },
+ { "geschw", fld_speed, STR_ANY }, /* speed in german */
{ "tempf", fld_temperature_f, STR_EQUAL }, /* degrees fahrenheit */
{ "temp", fld_temperature, STR_ANY }, /* degrees celsius by default */
{ "heart", fld_heartrate, STR_ANY },
- { "cadence", fld_cadence, STR_ANY },
+ { "caden", fld_cadence, STR_ANY },
{ "prox", fld_proximity, STR_ANY },
{ "depth", fld_depth, STR_ANY },
+ { "date", fld_date, STR_ANY },
+ { "time", fld_time, STR_ANY },
+ /* unhandled columns */
+ { "index", fld_terminator, STR_ANY },
+ { "no", fld_terminator, STR_EQUAL },
{ NULL, fld_terminator, 0 }
};
static int unicsv_fields_tab_ct;
static double unicsv_altscale;
static char *unicsv_fieldsep;
-static gbfile *file_in;
+static gbfile *fin, *fout;
static gpsdata_type unicsv_data_type;
-static route_head *unicsv_track;
+static route_head *unicsv_track, *unicsv_route;
+static unsigned long long unicsv_outp_flags;
+static grid_type unicsv_grid_idx;
+static int unicsv_datum_idx;
+static char *opt_datum, *opt_grid;
+static int unicsv_waypt_ct;
+static char unicsv_detect;
-static arglist_t unicsv_args[] = { ARG_TERMINATOR };
+static arglist_t unicsv_args[] = {
+ {"datum", &opt_datum, "GPS datum (def. WGS 84)",
+ "WGS 84", ARGTYPE_STRING, ARG_NOMINMAX},
+ {"grid", &opt_grid, "Write position using this grid.",
+ NULL, ARGTYPE_STRING, ARG_NOMINMAX},
+ ARG_TERMINATOR };
/* helpers */
// #define UNICSV_IS(f) (0 == strcmp(s, f))
#define UNICSV_CONTAINS(f) (0 != strstr(s, f))
+/* here we only need a simple yes(0) or no(1) */
+static int
+unicsv_strrcmp(const char *s1, const char *s2)
+{
+ int l1, l2;
+
+ l1 = strlen(s1);
+ l2 = strlen(s2);
+ if ((l1 - l2) >= 0)
+ return strcmp(s1 + (l1 - l2), s2);
+ else
+ return 1; /* false */
+}
+
+static int
+unicsv_parse_date(const char *str)
+{
+ int p1, p2, p3, ct;
+ char sep[2];
+ struct tm tm;
+
+ memset(&tm, 0, sizeof(tm));
+ ct = sscanf(str, "%d%1[-.//]%d%1[-.//]%d", &p1, sep, &p2, sep, &p3);
+ is_fatal(ct != 5, MYNAME ": Could not parse date string (%s).", str);
+
+ if ((p1 > 99) || (sep[0] == '-')) { /* Y-M-D (iso like) */
+ tm.tm_year = p1;
+ tm.tm_mon = p2;
+ tm.tm_mday = p3;
+ }
+ else if (sep[0] == '.') { /* Germany any other countries */
+ tm.tm_mday = p1; /* have fixed D.M.Y format */
+ tm.tm_mon = p2;
+ tm.tm_year = p3;
+ }
+ else {
+ tm.tm_mday = p2;
+ tm.tm_mon = p1;
+ tm.tm_year = p3;
+ }
+ if ((p1 < 100) && (p2 < 100) && (p3 < 100)) {
+ if (tm.tm_year < 70) tm.tm_year += 2000;
+ else tm.tm_year += 1900;
+ }
+ /* some low-level checks */
+ if ((tm.tm_mon > 12) || (tm.tm_mon < 1) || (tm.tm_mday > 31) || (tm.tm_mday < 1))
+ fatal(MYNAME ": Could not parse date string (%s).\n", str);
+
+ tm.tm_year -= 1900;
+ tm.tm_mon -= 1;
+
+ return mkgmtime(&tm);
+}
+
+static int
+unicsv_parse_time(const char *str, int *msec)
+{
+ int hour, min, ct;
+ double sec;
+ char sep[2];
+
+ ct = sscanf(str, "%d%1[.://]%d%1[.://]%lf", &hour, sep, &min, sep, &sec);
+ is_fatal(ct != 5, MYNAME ": Could not parse time string (%s).\n", str);
+ *msec = (sec - (int)sec) * 1000000;
+ return ((hour * SECONDS_PER_HOUR) + (min * 60) + (int)sec);
+}
+
static char
unicsv_compare_fields(char *s, const field_t *f)
{
result = (strstr(test, name) != NULL);
}
else {
- int len = strlen(name);
-
if (f->options & STR_LEFT) {
- result = (strncmp(test, name, len) == 0);
+ result = (strncmp(test, name, strlen(name)) == 0);
}
-/*
else if (f->options & STR_RIGHT) {
- result = (strrncmp(test, name, len) == 0);
+ result = (unicsv_strrcmp(test, name) == 0);
}
-*/
else {
- result = 0; /* what should we do here ? */
+ result = 0; /* fallback to "FALSE" */
}
}
if ((! result) && (strchr(test, ' ') != NULL)) {
+ /* replace ' ' with '_' and try again */
char *tmp = gstrsub(test, " ", "_");
result = unicsv_compare_fields(tmp, f);
xfree(tmp);
}
-
+ if ((! result) && (strchr(test, '-') != NULL)) {
+ /* replace '-' with '_' and try again */
+ char *tmp = gstrsub(test, "-", "_");
+ result = unicsv_compare_fields(tmp, f);
+ xfree(tmp);
+ }
+
if (name != f->name) {
xfree(name);
xfree(test);
unicsv_fondle_header(char *ibuf)
{
char *s;
+ char *buf = NULL;
int i, column;
+ const cet_cs_vec_t *ascii = &cet_cs_vec_ansi_x3_4_1968; /* us-ascii */
/* Convert the entire header to lower case for convenience.
* If we see a tab in that header, we decree it to be tabsep.
else if (*s == ';') {
unicsv_fieldsep = ";";
}
+ else if (*s == '|') {
+ unicsv_fieldsep = "|";
+ }
else {
- *s = tolower(*s);
+ continue;
}
+ break;
+ }
+ for (s = ibuf; *s; s++) {
+ *s = tolower(*s);
+ }
+
+ /* convert the header line into native ascii */
+ if (global_opts.charset != ascii) {
+ buf = cet_str_any_to_any(ibuf, global_opts.charset, ascii);
+ ibuf = buf;
}
column = -1;
- while ((s = csv_lineparse(ibuf, unicsv_fieldsep, "", 0))) {
+ while ((s = csv_lineparse(ibuf, unicsv_fieldsep, "\"", 0))) {
field_t *f = &fields_def[0];
}
f++;
}
+ if ((! f->name) && global_opts.debug_level)
+ warning(MYNAME ": Unhandled column \"%s\".\n", s);
/* handle some special items */
if (f->type == fld_altitude) {
unicsv_altscale = FEET_TO_METERS(1);
}
}
-/* todo: date, time, maybe a few others */
+ if ((f->type == fld_time) || (f->type == fld_date)) {
+ if (UNICSV_CONTAINS("iso"))
+ f->type = fld_iso_time;
+ }
}
+ if (buf) xfree(buf);
}
static void
unicsv_fields_tab = NULL;
unicsv_fields_tab_ct = 0;
- unicsv_data_type = wptdata;
- unicsv_track = NULL;
+ unicsv_data_type = global_opts.objective;
+ unicsv_detect = (! (global_opts.masked_objective & (WPTDATAMASK | TRKDATAMASK | RTEDATAMASK | POSNDATAMASK)));
- file_in = gbfopen(fname, "rb", MYNAME);
+ unicsv_track = unicsv_route = NULL;
+ unicsv_datum_idx = gt_lookup_datum_index(opt_datum, MYNAME);
- if ((c = gbfgetstr(file_in)))
+ fin = gbfopen(fname, "rb", MYNAME);
+
+ if ((c = gbfgetstr(fin)))
unicsv_fondle_header(c);
else
unicsv_fieldsep = NULL;
static void
unicsv_rd_deinit(void)
{
- gbfclose(file_in);
+ gbfclose(fin);
if (unicsv_fields_tab) xfree(unicsv_fields_tab);
}
char *s;
waypoint *wpt = NULL;
int column;
- int utmz = -9999;
- double utme = 0;
- double utmn = 0;
- char utmc = 'N';
+ int utm_zone = -9999;
+ double utm_easting = 0;
+ double utm_northing = 0;
+ char utm_zc = 'N';
char bng_zone[3] = "";
double bng_easting = 0;
double bng_northing = 0;
- struct tm tm;
- char *ok;
int checked = 0;
+ int date = -1, time = -1, msec = -1;
+ char is_localtime = 0;
wpt = waypt_new();
+ wpt->latitude = -9999;
+ wpt->longitude = -9999;
+
column = -1;
while ((s = csv_lineparse(ibuf, unicsv_fieldsep, "\"", 0))) {
- if (column > unicsv_fields_tab_ct) break; /* extra fields on line */
+ if (column > unicsv_fields_tab_ct) break; /* ignore extra fields on line */
ibuf = NULL;
+
column++;
checked++;
+
s = lrtrim(s);
+ if (! *s) continue; /* skip empty columns */
+
+ switch(unicsv_fields_tab[column]) {
+
+ case fld_time:
+ case fld_date:
+ /* switch column type if it looks like an iso time string */
+ if (strchr(s, 'T'))
+ unicsv_fields_tab[column] = fld_iso_time;
+ break;
+ default: ;
+ }
+
switch(unicsv_fields_tab[column]) {
break;
case fld_shortname:
- if (*s) wpt->shortname = xstrdup(s);
+ wpt->shortname = xstrdup(s);
break;
case fld_description:
- if (*s) wpt->description = xstrdup(s);
+ wpt->description = xstrdup(s);
break;
case fld_notes:
- if (*s) wpt->notes = xstrdup(s);
+ wpt->notes = xstrdup(s);
break;
case fld_url:
- if (*s) wpt->url = xstrdup(s);
+ wpt->url = xstrdup(s);
break;
case fld_altitude:
break;
case fld_utm_zone:
- utmz = atoi(s);
+ utm_zone = atoi(s);
break;
case fld_utm_easting:
- utme = atof(s);
+ utm_easting = atof(s);
break;
case fld_utm_northing:
- utmn = atof(s);
+ utm_northing = atof(s);
break;
- case fld_utm_char:
- utmc = toupper(s[0]);
+ case fld_utm_zone_char:
+ utm_zc = toupper(s[0]);
break;
case fld_utm:
case fld_hdop:
wpt->hdop = atof(s);
- unicsv_data_type = trkdata;
+ if (unicsv_detect) unicsv_data_type = trkdata;
break;
case fld_pdop:
wpt->pdop = atof(s);
- unicsv_data_type = trkdata;
+ if (unicsv_detect) unicsv_data_type = trkdata;
break;
case fld_vdop:
wpt->vdop = atof(s);
- unicsv_data_type = trkdata;
+ if (unicsv_detect) unicsv_data_type = trkdata;
break;
case fld_sat:
wpt->sat = atoi(s);
- unicsv_data_type = trkdata;
+ if (unicsv_detect) unicsv_data_type = trkdata;
break;
case fld_fix:
- unicsv_data_type = trkdata;
+ if (unicsv_detect) unicsv_data_type = trkdata;
if (case_ignore_strcmp(s, "none") == 0)
wpt->fix = fix_none;
else if (case_ignore_strcmp(s, "2d") == 0)
break;
case fld_utc_date:
- memset(&tm, 0, sizeof(tm));
- if (strchr(s, '.'))
- ok = strptime(s, "%d.%m.%Y", &tm);
- else
- ok = strptime(s, "%d/%m/%Y", &tm);
- if (ok) {
- tm.tm_isdst = -1;
- wpt->creation_time += mkgmtime(&tm);
+ if ((is_localtime < 2) && (date < 0)) {
+ date = unicsv_parse_date(s);
+ is_localtime = 0;
}
- else
- fatal(MYNAME ": Could not convert date string (%s).\n", s);
break;
-
+
case fld_utc_time:
- memset(&tm, 0, sizeof(tm));
- if (strptime( s, "%H:%M:%S", &tm)) {
- wpt->creation_time += (
- (SECONDS_PER_HOUR * tm.tm_hour) +
- (60L * tm.tm_min) + tm.tm_sec
- );
+ if ((is_localtime < 2) && (time < 0)) {
+ time = unicsv_parse_time(s, &msec);
+ is_localtime = 0;
}
break;
case fld_speed:
WAYPT_SET(wpt, speed, atof(s));
- unicsv_data_type = trkdata;
+ if (unicsv_detect) unicsv_data_type = trkdata;
break;
case fld_course:
WAYPT_SET(wpt, course, atof(s));
- unicsv_data_type = trkdata;
+ if (unicsv_detect) unicsv_data_type = trkdata;
break;
case fld_temperature:
case fld_heartrate:
wpt->heartrate = atoi(s);
- unicsv_data_type = trkdata;
+ if (unicsv_detect) unicsv_data_type = trkdata;
break;
case fld_cadence:
wpt->cadence = atoi(s);
- unicsv_data_type = trkdata;
+ if (unicsv_detect) unicsv_data_type = trkdata;
break;
case fld_proximity:
WAYPT_SET(wpt, depth, atof(s));
break;
+ case fld_symbol:
+ wpt->icon_descr = xstrdup(s);
+ wpt->wpt_flags.icon_descr_is_dynamic = 1;
+ break;
+
+ case fld_iso_time:
+ is_localtime = 2; /* fix result */
+ wpt->creation_time = xml_parse_time(s, &wpt->microseconds);
+ break;
+
+ case fld_time:
+ if ((is_localtime < 2) && (time < 0)) {
+ time = unicsv_parse_time(s, &msec);
+ is_localtime = 1;
+ }
+ break;
+
+ case fld_date:
+ if ((is_localtime < 2) && (date < 0)) {
+ date = unicsv_parse_date(s);
+ is_localtime = 1;
+ }
+ break;
+
+ case fld_datetime:
+ /* not implemented */
+ break;
+
case fld_terminator: /* dummy */
checked--;
break;
return;
}
- if (utmz != -9999) {
- GPS_Math_UTM_EN_To_Known_Datum(&wpt->latitude, &wpt->longitude,
- utme, utmn, utmz, utmc, DATUM_WGS84);
+ if (is_localtime < 2) { /* not fixed */
+ if ((time >= 0) && (date >= 0)) {
+ time_t t = date + time;
+
+ if (is_localtime) {
+ struct tm tm;
+ tm = *gmtime(&t);
+ wpt->creation_time = mklocaltime(&tm);
+ }
+ else
+ wpt->creation_time = t;
+ }
+ else if (time >= 0)
+ wpt->creation_time = time;
+ else if (date >= 0)
+ wpt->creation_time = date;
+ if (msec >= 0)
+ wpt->microseconds = msec;
}
-
- if (bng_zone[0]) {
- if (! GPS_Math_UKOSMap_To_WGS84_M(
+
+ /* utm/bng can be optional */
+ if ((wpt->latitude == -9999) && (wpt->longitude == -9999)) {
+ if (utm_zone != -9999) {
+ GPS_Math_UTM_EN_To_Known_Datum(&wpt->latitude, &wpt->longitude,
+ utm_easting, utm_northing, utm_zone, utm_zc, DATUM_WGS84);
+ }
+ else if (bng_zone[0]) {
+ if (! GPS_Math_UKOSMap_To_WGS84_M(
bng_zone, bng_easting, bng_northing,
&wpt->latitude, &wpt->longitude))
fatal(MYNAME ": Unable to convert BNG coordinates (%s %.f %.f)!\n",
bng_zone, bng_easting, bng_northing);
+ }
}
switch(unicsv_data_type) {
- case trkdata:
- if (! unicsv_track) {
- unicsv_track = route_head_alloc();
- track_add_head(unicsv_track);
- }
- track_add_wpt(unicsv_track, wpt);
- break;
- default:
- waypt_add(wpt);
+ case rtedata:
+ if (! unicsv_route) {
+ unicsv_route = route_head_alloc();
+ route_add_head(unicsv_route);
+ }
+ route_add_wpt(unicsv_route, wpt);
+ break;
+ case trkdata:
+ if (! unicsv_track) {
+ unicsv_track = route_head_alloc();
+ track_add_head(unicsv_track);
+ }
+ track_add_wpt(unicsv_track, wpt);
+ break;
+ default:
+ waypt_add(wpt);
}
}
if (unicsv_fieldsep == NULL) return;
- while ((buff = gbfgetstr(file_in))) {
+ while ((buff = gbfgetstr(fin))) {
buff = lrtrim(buff);
- if (*buff)
- unicsv_parse_one_line(buff);
+ if ((*buff == '\0') || (*buff == '#')) continue;
+ unicsv_parse_one_line(buff);
+ }
+}
+
+/* =========================================================================== */
+
+static char *
+strenquote(const char *str, const char quot_char)
+{
+ int len;
+ char *cin, *cout;
+ char *tmp;
+
+ if (str == NULL) cin = "";
+ else cin = (char *)str;
+
+ len = strlen(cin);
+ cout = tmp = xmalloc((len * 2) + 3);
+
+ *cout++ = quot_char;
+ while (*cin) {
+ *cout++ = *cin;
+ if (*cin++ == quot_char)
+ *cout++ = quot_char;
+ }
+ *cout++ = quot_char;
+ *cout = '\0';
+
+ cout = xstrdup(tmp);
+ xfree(tmp);
+ return cout;
+}
+
+static void
+unicsv_print_str(const char *str)
+{
+ if (str && *str) {
+ char *cout;
+
+ cout = strenquote(str, UNICSV_QUOT_CHAR);
+ gbfprintf(fout, "%s%s", unicsv_fieldsep, cout);
+ xfree(cout);
+ }
+ else gbfputs(unicsv_fieldsep, fout);
+}
+
+#define BIT_OF(a) (1ULL << a)
+#define FIELD_USED(a) (unicsv_outp_flags & (1ULL << a))
+
+static void
+unicsv_waypt_enum_cb(const waypoint *wpt)
+{
+ char *shortname = (wpt->shortname) ? wpt->shortname : "";
+
+ if (*shortname) unicsv_outp_flags |= BIT_OF(fld_shortname);
+ if (wpt->altitude != unknown_alt) unicsv_outp_flags |= BIT_OF(fld_altitude);
+ if (wpt->icon_descr && *wpt->icon_descr) unicsv_outp_flags |= BIT_OF(fld_symbol);
+ if (wpt->description && *wpt->description && (strcmp(shortname, wpt->description) != 0))
+ unicsv_outp_flags |= BIT_OF(fld_description);
+ if (wpt->notes && *wpt->notes && (strcmp(shortname, wpt->notes) != 0)) {
+ if ((! wpt->description) || (strcmp(wpt->description, wpt->notes) != 0))
+ unicsv_outp_flags |= BIT_OF(fld_notes);
+ }
+ if (wpt->url && *wpt->url) unicsv_outp_flags |= BIT_OF(fld_url);
+ if (wpt->creation_time != 0) {
+ unicsv_outp_flags |= BIT_OF(fld_time);
+ if (wpt->creation_time >= SECONDS_PER_DAY)
+ unicsv_outp_flags |= BIT_OF(fld_date);
+ }
+
+ if (wpt->vdop > 0) unicsv_outp_flags |= BIT_OF(fld_vdop);
+ if (wpt->hdop > 0) unicsv_outp_flags |= BIT_OF(fld_hdop);
+ if (wpt->pdop > 0) unicsv_outp_flags |= BIT_OF(fld_pdop);
+ if (wpt->sat > 0) unicsv_outp_flags |= BIT_OF(fld_sat);
+ if (wpt->heartrate != 0) unicsv_outp_flags |= BIT_OF(fld_heartrate);
+ if (wpt->cadence != 0) unicsv_outp_flags |= BIT_OF(fld_cadence);
+
+ /* "flagged" waypoint members */
+ if WAYPT_HAS(wpt, course) unicsv_outp_flags |= BIT_OF(fld_course);
+ if WAYPT_HAS(wpt, depth) unicsv_outp_flags |= BIT_OF(fld_depth);
+ if WAYPT_HAS(wpt, speed) unicsv_outp_flags |= BIT_OF(fld_speed);
+ if WAYPT_HAS(wpt, proximity) unicsv_outp_flags |= BIT_OF(fld_proximity);
+ if WAYPT_HAS(wpt, temperature) unicsv_outp_flags |= BIT_OF(fld_temperature);
+}
+
+static void
+unicsv_waypt_disp_cb(const waypoint *wpt)
+{
+ double lat, lon, alt;
+ char *cout;
+ char *shortname = (wpt->shortname) ? wpt->shortname : "";
+
+ unicsv_waypt_ct++;
+
+ if (unicsv_datum_idx == DATUM_WGS84) {
+ lat = wpt->latitude;
+ lon = wpt->longitude;
+ alt = wpt->altitude;
+ }
+ else {
+ GPS_Math_WGS84_To_Known_Datum_M(wpt->latitude, wpt->longitude, 0.0,
+ &lat, &lon, &alt, unicsv_datum_idx);
+ }
+
+ gbfprintf(fout, "%d%s", unicsv_waypt_ct, unicsv_fieldsep);
+
+ switch(unicsv_grid_idx) {
+
+ case grid_lat_lon_ddd:
+ cout = pretty_deg_format(lat, lon, 'd', unicsv_fieldsep, 0);
+ gbfputs(cout, fout);
+ xfree(cout);
+ break;
+
+ case grid_lat_lon_dmm:
+ cout = pretty_deg_format(lat, lon, 'm', unicsv_fieldsep, 0);
+ gbfputs(cout, fout);
+ xfree(cout);
+ break;
+
+ case grid_lat_lon_dms:
+ cout = pretty_deg_format(lat, lon, 's', unicsv_fieldsep, 0);
+ gbfputs(cout, fout);
+ xfree(cout);
+ break;
+
+ case grid_bng: {
+ char map[3];
+ double north, east;
+
+ if (! GPS_Math_WGS84_To_UKOSMap_M(wpt->latitude, wpt->longitude, &east, &north, map))
+ fatal(MYNAME ": Some (or all?) of the coordinates cannot be displayed using \"BNG\".\n");
+ gbfprintf(fout, "%s%s%5.0f%s%5.0f",
+ map, unicsv_fieldsep,
+ east, unicsv_fieldsep,
+ north);
+ break;
+ }
+ case grid_utm: {
+ int zone;
+ char zonec;
+ double north, east;
+
+ if (! GPS_Math_Known_Datum_To_UTM_EN(lat, lon,
+ &east, &north, &zone, &zonec, unicsv_datum_idx))
+ fatal(MYNAME ": Some (or all?) of the coordinates cannot be displayed using \"UTM\".\n");
+ gbfprintf(fout, "%02d%s%c%s%.0f%s%.0f",
+ zone, unicsv_fieldsep,
+ zonec, unicsv_fieldsep,
+ east, unicsv_fieldsep,
+ north);
+ break;
+ }
+ default:
+ gbfprintf(fout, "%.6f%s%.6f", lat, unicsv_fieldsep, lon);
+ break;
+ }
+
+ if FIELD_USED(fld_shortname) unicsv_print_str(shortname);
+ if FIELD_USED(fld_altitude) {
+ if (wpt->altitude != unknown_alt)
+ gbfprintf(fout, "%s%.1f", unicsv_fieldsep, wpt->altitude);
+ else
+ gbfputs(unicsv_fieldsep, fout);
+ }
+ if FIELD_USED(fld_description) unicsv_print_str(wpt->description);
+ if FIELD_USED(fld_notes) unicsv_print_str(wpt->notes);
+ if FIELD_USED(fld_symbol)
+ unicsv_print_str((wpt->icon_descr != NULL) ? wpt->icon_descr : "Waypoint");
+ if FIELD_USED(fld_depth) {
+ if WAYPT_HAS(wpt, depth)
+ gbfprintf(fout, "%s%.1f", unicsv_fieldsep, wpt->depth);
+ else
+ gbfputs(unicsv_fieldsep, fout);
+ }
+ if FIELD_USED(fld_proximity) {
+ if WAYPT_HAS(wpt, proximity)
+ gbfprintf(fout, "%s%.f", unicsv_fieldsep, wpt->proximity);
+ else
+ gbfputs(unicsv_fieldsep, fout);
+ }
+ if FIELD_USED(fld_temperature) {
+ if WAYPT_HAS(wpt, temperature)
+ gbfprintf(fout, "%s%.1f", unicsv_fieldsep, wpt->temperature);
+ else
+ gbfputs(unicsv_fieldsep, fout);
+ }
+ if FIELD_USED(fld_speed) {
+ if WAYPT_HAS(wpt, speed)
+ gbfprintf(fout, "%s%.1f", unicsv_fieldsep, wpt->speed);
+ else
+ gbfputs(unicsv_fieldsep, fout);
+ }
+ if FIELD_USED(fld_course) {
+ if WAYPT_HAS(wpt, course)
+ gbfprintf(fout, "%s%.1f", unicsv_fieldsep, wpt->course);
+ else
+ gbfputs(unicsv_fieldsep, fout);
+ }
+ if FIELD_USED(fld_hdop) {
+ if (wpt->hdop > 0)
+ gbfprintf(fout, "%s%.1f", unicsv_fieldsep, wpt->hdop);
+ else
+ gbfputs(unicsv_fieldsep, fout);
+ }
+ if FIELD_USED(fld_vdop) {
+ if (wpt->vdop > 0)
+ gbfprintf(fout, "%s%.1f", unicsv_fieldsep, wpt->vdop);
+ else
+ gbfputs(unicsv_fieldsep, fout);
+ }
+ if FIELD_USED(fld_pdop) {
+ if (wpt->pdop > 0)
+ gbfprintf(fout, "%s%.1f", unicsv_fieldsep, wpt->pdop);
+ else
+ gbfputs(unicsv_fieldsep, fout);
+ }
+ if FIELD_USED(fld_sat) {
+ if (wpt->sat > 0)
+ gbfprintf(fout, "%s%d", unicsv_fieldsep, wpt->sat);
+ else
+ gbfputs(unicsv_fieldsep, fout);
+ }
+ if FIELD_USED(fld_heartrate) {
+ if (wpt->heartrate != 0)
+ gbfprintf(fout, "%s%u", unicsv_fieldsep, wpt->heartrate);
+ else
+ gbfputs(unicsv_fieldsep, fout);
+ }
+ if FIELD_USED(fld_cadence) {
+ if (wpt->cadence != 0)
+ gbfprintf(fout, "%s%u", unicsv_fieldsep, wpt->cadence);
+ else
+ gbfputs(unicsv_fieldsep, fout);
+ }
+ if FIELD_USED(fld_date) {
+ if (wpt->creation_time >= SECONDS_PER_DAY) {
+ struct tm tm;
+ char buf[32];
+ tm = *localtime(&wpt->creation_time);
+ tm.tm_year += 1900;
+ tm.tm_mon += 1;
+ snprintf(buf, sizeof(buf), "%04d/%02d/%02d", tm.tm_year, tm.tm_mon, tm.tm_mday);
+ gbfprintf(fout, "%s%s", unicsv_fieldsep, buf);
+ }
+ else
+ gbfputs(unicsv_fieldsep, fout);
+ }
+ if FIELD_USED(fld_time) {
+ if (wpt->creation_time != 0) {
+ struct tm tm;
+ char buf[32], msec[12];
+ tm = *localtime(&wpt->creation_time);
+ snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec);
+ if (wpt->microseconds > 0) {
+ snprintf(msec, sizeof(msec), ".%d", wpt->microseconds / 1000);
+ strcat(buf, msec);
+ }
+ gbfprintf(fout, "%s%s", unicsv_fieldsep, buf);
+ }
+ else
+ gbfputs(unicsv_fieldsep, fout);
+ }
+ if FIELD_USED(fld_url) unicsv_print_str(wpt->url);
+
+ gbfputs(UNICSV_LINE_SEP, fout);
+}
+
+/* --------------------------------------------------------------------------- */
+
+
+static void
+unicsv_wr_init(const char *filename)
+{
+ fout = gbfopen(filename, "w", MYNAME);
+
+ unicsv_outp_flags = 0;
+ unicsv_grid_idx = grid_unknown;
+ unicsv_datum_idx = DATUM_WGS84;
+ unicsv_fieldsep = UNICSV_FIELD_SEP;
+ unicsv_waypt_ct = 0;
+
+ if (opt_grid != NULL) {
+ int i;
+
+ if (sscanf(opt_grid, "%d", &i)) {
+ unicsv_grid_idx = (grid_type) i;
+ if ((unicsv_grid_idx < GRID_INDEX_MIN) || (unicsv_grid_idx > GRID_INDEX_MAX))
+ fatal(MYNAME ": Grid index out of range (%d..%d)!\n",
+ (int)GRID_INDEX_MIN, (int)GRID_INDEX_MAX);
+ }
+ else unicsv_grid_idx = gt_lookup_grid_type(opt_grid, MYNAME);
+ }
+
+ if (unicsv_grid_idx == grid_bng)
+ /* force datum to "Ord Srvy Grt Britn" / OSGB36 */
+ /* ! ignore parameter "Datum" ! */
+ unicsv_datum_idx = DATUM_OSGB36;
+ else
+ unicsv_datum_idx = gt_lookup_datum_index(opt_datum, MYNAME);
+}
+
+static void
+unicsv_wr_deinit(void)
+{
+ gbfclose(fout);
+}
+
+static void
+unicsv_wr(void)
+{
+ switch(global_opts.objective) {
+ case wptdata:
+ waypt_disp_all(unicsv_waypt_enum_cb);
+ break;
+ case trkdata:
+ track_disp_all(NULL, NULL, unicsv_waypt_enum_cb);
+ break;
+ case rtedata:
+ route_disp_all(NULL, NULL, unicsv_waypt_enum_cb);
+ break;
+ case posndata:
+ fatal(MYNAME ": Realtime positioning not supported.\n");
+ }
+
+ gbfprintf(fout, "No%s", unicsv_fieldsep);
+
+ switch(unicsv_grid_idx) {
+ case grid_bng:
+ gbfprintf(fout, "BNG-Zone%1$sBNG-East%1$sBNG-North", unicsv_fieldsep);
+ break;
+ case grid_utm:
+ gbfprintf(fout, "UTM-Zone%1$sUTM-Ch%1$sUTM-East%1$sUTM-North", unicsv_fieldsep);
+ break;
+ default:
+ gbfprintf(fout, "Latitude%sLongitude", unicsv_fieldsep);
+ }
+
+ if FIELD_USED(fld_shortname) gbfprintf(fout, "%sName", unicsv_fieldsep);
+ if FIELD_USED(fld_altitude) gbfprintf(fout, "%sAltitude", unicsv_fieldsep);
+ if FIELD_USED(fld_description) gbfprintf(fout, "%sDescription", unicsv_fieldsep);
+ if FIELD_USED(fld_notes) gbfprintf(fout, "%sNotes", unicsv_fieldsep);
+ if FIELD_USED(fld_symbol) gbfprintf(fout, "%sSymbol", unicsv_fieldsep);
+ if FIELD_USED(fld_depth) gbfprintf(fout, "%sDepth", unicsv_fieldsep);
+ if FIELD_USED(fld_proximity) gbfprintf(fout, "%sProximity", unicsv_fieldsep);
+ if FIELD_USED(fld_temperature) gbfprintf(fout, "%sTemperature", unicsv_fieldsep);
+ if FIELD_USED(fld_speed) gbfprintf(fout, "%sSpeed", unicsv_fieldsep);
+ if FIELD_USED(fld_course) gbfprintf(fout, "%sCourse", unicsv_fieldsep);
+ if FIELD_USED(fld_hdop) gbfprintf(fout, "%sHDOP", unicsv_fieldsep);
+ if FIELD_USED(fld_vdop) gbfprintf(fout, "%sVDOP", unicsv_fieldsep);
+ if FIELD_USED(fld_pdop) gbfprintf(fout, "%sPDOP", unicsv_fieldsep);
+ if FIELD_USED(fld_sat) gbfprintf(fout, "%sSatellites", unicsv_fieldsep);
+ if FIELD_USED(fld_heartrate) gbfprintf(fout, "%sHeartrate", unicsv_fieldsep);
+ if FIELD_USED(fld_cadence) gbfprintf(fout, "%sCadence", unicsv_fieldsep);
+ if FIELD_USED(fld_date) gbfprintf(fout, "%sDate", unicsv_fieldsep);
+ if FIELD_USED(fld_time) gbfprintf(fout, "%sTime", unicsv_fieldsep);
+ if FIELD_USED(fld_url) gbfprintf(fout, "%sURL", unicsv_fieldsep);
+
+ gbfputs(UNICSV_LINE_SEP, fout);
+
+ switch(global_opts.objective) {
+ case wptdata:
+ waypt_disp_all(unicsv_waypt_disp_cb);
+ break;
+ case trkdata:
+ track_disp_all(NULL, NULL, unicsv_waypt_disp_cb);
+ break;
+ case rtedata:
+ route_disp_all(NULL, NULL, unicsv_waypt_disp_cb);
+ break;
+ default:
+ break;
}
}
ff_vecs_t unicsv_vecs = {
ff_type_file,
- { ff_cap_read, 0, 0},
+ FF_CAP_RW_ALL,
unicsv_rd_init,
- NULL,
+ unicsv_wr_init,
unicsv_rd_deinit,
- NULL,
+ unicsv_wr_deinit,
unicsv_rd,
- NULL,
+ unicsv_wr,
NULL,
unicsv_args,
CET_CHARSET_ASCII, 0 /* can be changed with -c ... */